package com.gome.ss.flowcrawl.plugin;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;

import com.gome.ss.common.AppConfiguer;
import com.gome.ss.common.Utils;
import com.gome.ss.core.plugin.PluginManager;
import com.gome.ss.core.plugin.SpiderLocalPluginConfig;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.util.JSON;

public class FlowCrawlManager {
	private static Logger logger = Logger.getLogger(FlowCrawlManager.class);
	
	public static void initFlowCrawlPlugin() {
		DBCollection collection = AppConfiguer.flowCrawlConfigMongo.getDB(AppConfiguer.FLOWCRAWL_DB_NAME)
				 .getCollection(AppConfiguer.FLOWCRAWL_CONFIG_COLLECTION_NAME);
		DBCursor cursor = collection.find();
		
		while(cursor.hasNext()) {
			DBObject obj = cursor.next();
			Boolean isLoad = (Boolean) obj.get("isLoad");
			String name = (String) obj.get("name");
			Boolean remove = obj.get("remove") == null ? false : (Boolean) obj.get("remove");
			if (isLoad && !remove)
				FlowCrawlManager.load(name);
		}
	}
	
	public static boolean add(String pluginName, String crawlInfo) {
		DBObject obj = (BasicDBObject) JSON.parse(crawlInfo);
		DBCollection collection = AppConfiguer.flowCrawlConfigMongo.getDB(AppConfiguer.FLOWCRAWL_DB_NAME)
				 .getCollection(AppConfiguer.FLOWCRAWL_CONFIG_COLLECTION_NAME);
		
		BasicDBObject query = new BasicDBObject("name", pluginName);
		DBCursor cursor = collection.find(query);
		
		if (cursor.count() > 0) {
			while (cursor.hasNext()) {
				DBObject oldobj = cursor.next();
				collection.remove(oldobj);
			}
		}
		
		obj.removeField("_id");
		
		collection.insert(obj);
		return true;
	}
	
	public static boolean copy(String oldName, String newName, String crawlInfo) {
		DBObject obj = (BasicDBObject) JSON.parse(crawlInfo);
		DBCollection collection = AppConfiguer.flowCrawlConfigMongo.getDB(AppConfiguer.FLOWCRAWL_DB_NAME)
				 .getCollection(AppConfiguer.FLOWCRAWL_CONFIG_COLLECTION_NAME);
		
		BasicDBObject query = new BasicDBObject("name", newName);
		DBCursor cursor = collection.find(query);
		
		if (cursor.count() > 0) {
			while (cursor.hasNext()) {
				DBObject oldobj = cursor.next();
				collection.remove(oldobj);
			}
		}
		
		obj.removeField("_id");
		
		collection.insert(obj);
		
		List<DBObject> stepObjs = (List<DBObject>) obj.get("steps");
		for (DBObject so : stepObjs) {
			if (so.get("stepID") != null) {
				String stepID = (String) so.get("stepID");
				copyExtractorConfig(oldName, newName, stepID);
			}
		}
		
		return true;
	}
	
	private static void copyExtractorConfig(String oldName, String newName, String stepID) {
		DBCollection collection = AppConfiguer.flowCrawlConfigMongo.getDB(AppConfiguer.FLOWCRAWL_DB_NAME)
				 .getCollection(AppConfiguer.FLOWCRAWL_EXTRACT_COLLECTION_NAME);
		BasicDBObject query = new BasicDBObject();
		query.put("name", oldName);
		query.put("stepID", stepID);
		
		DBCursor cursor = collection.find(query);
		
		if (cursor.count() > 0) {
			DBObject obj = cursor.next();
			obj.removeField("_id");
			obj.put("name", newName);
			collection.insert(obj);
		}
	}
	
	
	private static void removeExtractorConfig(String name, String stepID) {
		DBCollection collection = AppConfiguer.flowCrawlConfigMongo.getDB(AppConfiguer.FLOWCRAWL_DB_NAME)
				 .getCollection(AppConfiguer.FLOWCRAWL_EXTRACT_COLLECTION_NAME);
		BasicDBObject query = new BasicDBObject();
		query.put("name", name);
		query.put("stepID", stepID);
		
		DBCursor cursor = collection.find(query);
		
		if (cursor.count() > 0) {
			DBObject obj = cursor.next();
			collection.remove(obj);
		}
	}
	
	public static String info(String pluginNameString, String pluginNameQueryString) {
		DBCollection collection = AppConfiguer.flowCrawlConfigMongo.getDB(AppConfiguer.FLOWCRAWL_DB_NAME)
				.getCollection(AppConfiguer.FLOWCRAWL_CONFIG_COLLECTION_NAME);
		
		if (pluginNameString != null) {
			if (!pluginNameString.isEmpty()) {
				BasicDBObject query = new BasicDBObject("name", pluginNameString);
				DBCursor cursor = collection.find(query);
				
				if (cursor.count() > 0) {
					DBObject obj = cursor.next();
					Boolean remove = obj.get("remove") == null ? false : (Boolean) obj.get("remove");
					if (remove)
						return AppConfiguer.NULL_JSON_OBJECT;
					return JSON.serialize(obj);
				}
			}
			
			return AppConfiguer.NULL_JSON_OBJECT;
		} else if (pluginNameQueryString != null) {
			if (!pluginNameQueryString.isEmpty()) {
				BasicDBObject query = new BasicDBObject("name", getLike(pluginNameQueryString));
				DBCursor cursor = collection.find(query);
				
				List<DBObject> array = new ArrayList<DBObject>();
				
				while(cursor.hasNext()) {
					DBObject obj = cursor.next();
					Boolean remove = obj.get("remove") == null ? false : (Boolean) obj.get("remove");
					if (!remove)
						array.add(obj);
				}
				return JSON.serialize(array);
			}
			
			return AppConfiguer.NULL_JSON_ARRAY;
		}
		
		return "";
	}
	
	public static String list(String pagenoString, String perpageString) {
		
		int pageno = 0;
		int perpage = 0;
		
		try {
			pageno = Integer.valueOf(pagenoString);
			perpage = Integer.valueOf(perpageString);
		} catch (Exception e) {
			logger.error(Utils.getTrace(e));
			return AppConfiguer.NULL_JSON_ARRAY;
		}
		
		DBCollection collection = AppConfiguer.flowCrawlConfigMongo.getDB(AppConfiguer.FLOWCRAWL_DB_NAME)
				.getCollection(AppConfiguer.FLOWCRAWL_CONFIG_COLLECTION_NAME);
		
		DBCursor cursor = collection.find().skip((pageno - 1) * perpage).sort(new BasicDBObject()).limit(perpage);
		
		List<DBObject> results = new ArrayList<DBObject>();
		while (cursor.hasNext()) {
			DBObject obj = cursor.next();
			Boolean remove = obj.get("remove") == null ? false : (Boolean) obj.get("remove");
			if (!remove)
				results.add(obj);
		}
		
		return JSON.serialize(results);
	}
	
	public static boolean load(String pluginNameString) {
		
		DBCollection collection = AppConfiguer.flowCrawlConfigMongo.getDB(AppConfiguer.FLOWCRAWL_DB_NAME)
				.getCollection(AppConfiguer.FLOWCRAWL_CONFIG_COLLECTION_NAME);

		if (pluginNameString != null && !pluginNameString.isEmpty()) {
			BasicDBObject query = new BasicDBObject("name", pluginNameString);
			DBCursor cursor = collection.find(query);
			
			if (cursor.count() > 0) {
				DBObject obj = cursor.next();
				Boolean remove = obj.get("remove") == null ? false : (Boolean) obj.get("remove");
				if (remove)
					return false;
				
				SpiderLocalPluginConfig config = new SpiderLocalPluginConfig(obj);
				
				try {
					PluginManager.getInstance().loadLocalPlugin(config, true);
					if (PluginManager.getInstance().getPlugin(pluginNameString) != null) {
						obj.removeField("_id");
						obj.put("isLoad", true);
						collection.update(query, obj);
					}
				} catch (Exception e) {
					// TODO Auto-generated catch block
					logger.error(Utils.getTrace(e));
					
					return false;
				}
				
				return true;
			}
		}
		
		return false;
	}
	
	public static boolean remove(String pluginNameString) {
		
		if (pluginNameString == null || pluginNameString.isEmpty()) {
			return false;
		}
		
		DBCollection collection = AppConfiguer.flowCrawlConfigMongo.getDB(AppConfiguer.FLOWCRAWL_DB_NAME)
				.getCollection(AppConfiguer.FLOWCRAWL_CONFIG_COLLECTION_NAME);
		
		BasicDBObject query = new BasicDBObject("name", pluginNameString);
		DBCursor cursor = collection.find(query);
		
		if (cursor.count() > 0) {
			DBObject obj = cursor.next();
			DBObject newObj = obj;
			newObj.put("remove", true);
			collection.update(query, newObj);
			
			List<DBObject> stepObjs = (List<DBObject>) obj.get("steps");
			for (DBObject so : stepObjs) {
				if (so.get("stepID") != null) {
					String stepID = (String) so.get("stepID");
					removeExtractorConfig(pluginNameString, stepID);
				}
			}
			
			logger.info("Remove plugin : " + pluginNameString + " success !");
			return true;
		}
		return false;
	}
	
	public static boolean unload(String pluginNameString) {
		if (pluginNameString == null || pluginNameString.isEmpty()) {
			return false;
		}
		
		DBCollection collection = AppConfiguer.flowCrawlConfigMongo.getDB(AppConfiguer.FLOWCRAWL_DB_NAME)
				.getCollection(AppConfiguer.FLOWCRAWL_CONFIG_COLLECTION_NAME);
		
		BasicDBObject query = new BasicDBObject("name", pluginNameString);
		DBCursor cursor = collection.find(query);
		
		if (cursor.count() > 0) {
			DBObject obj = cursor.next();
			
			obj.removeField("_id");
			obj.put("isLoad", false);
			collection.update(query, obj);
			
			return true;
		}
		return false;
	}
	
	private static BasicDBObject getLike(String findStr) {
		Pattern pattern = Pattern.compile("^.*" + findStr + ".*$", Pattern.MULTILINE);
	    return new BasicDBObject("$regex", pattern);
	}
	
}
